﻿using BouncingBallGame.ViewModels;
using BouncingBallGame.ViewModels.ShapeViewModels;
using Dpy.MathWinRT.Geometry.Geometry2D;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Dpy.MathWinRT;
using Dpy.MathWinRT.Algebra;

// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236

namespace BouncingBallGame.Views
{
    public sealed partial class EditLevelView : UserControl
    {
        private Point? StartDrawPoint { get; set; }

        private EditLevelViewModel ViewModel
        {
            get
            {
                return this.DataContext as EditLevelViewModel;
            }
        }

        public EditLevelView()
        {
            this.InitializeComponent();
        }

        private void Canvas_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
        {  
            if (this.StartDrawPoint == null)
            {
                return;
            }

            Point startPoint = (Point)this.StartDrawPoint;
            this.StartDrawPoint = null;
            Point endPoint = e.Position;

            Vector2D startVector = new Vector2D(startPoint.X, startPoint.Y);
            Vector2D endVector = new Vector2D(endPoint.X, endPoint.Y);

            Vector2D diagonal = startVector - endVector;

            if (Math.Abs(diagonal.X) > 5 && Math.Abs(diagonal.Y) > 5)
            {
                this.ViewModel.DrawShape(startPoint, endPoint);
            }
        }

        private void Canvas_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
        {
            if (e.OriginalSource as Canvas != sender as Canvas)
            {
                return;
            }

            this.StartDrawPoint = e.Position;
        }

        private void ShapeDrag_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.IsInertial)
            {
                return;
            }

            double offsetX = e.Delta.Translation.X;
            double offsetY = e.Delta.Translation.Y;

            FrameworkElement shape = sender as FrameworkElement;
            var viewModel = shape.DataContext as ShapeViewModelBase;

            if (viewModel != null)
            {
                viewModel.X += offsetX;
                viewModel.Y += offsetY;
                this.ViewModel.LastUsedShape = viewModel;
            }
        }

        private void RotateAndScale_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.IsInertial)
            {
                return;
            }

            FrameworkElement shape = sender as FrameworkElement;
            var viewModel = shape.DataContext as RectangleViewModel;

            if (viewModel != null)
            {                
                Vector2D globalTranslation = new Vector2D(e.Delta.Translation.X, e.Delta.Translation.Y);
                Vector2D localTranslation = globalTranslation.RotateClockWise(viewModel.Rotation * Math.PI / 180);

                Vector2D oldDiagonal = new Vector2D(viewModel.Width, viewModel.Height);
                Vector2D newDiagonal = oldDiagonal + localTranslation;
                double rotation = Vector2D.GetAngleInRadians(oldDiagonal, newDiagonal) * 180 / Math.PI;

                Matrix matrix = new Matrix(new double[,]{
                    {oldDiagonal.X, oldDiagonal.Y},
                    {newDiagonal.X, newDiagonal.Y},
                });

                double determinant = matrix.Determinant;
                int sign = determinant.IsZero() ? 0 :
                    (
                        determinant > 0
                        ? 1
                        : -1
                    );

                double scaleFactor = newDiagonal.Length / oldDiagonal.Length;

                double width = viewModel.Width * scaleFactor;
                double height = viewModel.Height * scaleFactor;

                if (height.IsRealNumber() && height > 5)
                {
                    viewModel.Height = height;
                }

                if (width.IsRealNumber() && width > 5)
                {
                    viewModel.Width = width;
                }

                if (rotation.IsRealNumber())
                {
                    viewModel.Rotation = viewModel.Rotation + sign * rotation;
                }

                this.ViewModel.LastUsedShape = viewModel;
            }
        }

        private void HeightScale_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.IsInertial)
            {
                return;
            }

            FrameworkElement shape = sender as FrameworkElement;
            var viewModel = shape.DataContext as RectangleViewModel;

            if (viewModel != null)
            {
                double rotation = viewModel.Rotation * Math.PI / 180;

                Vector2D globalTranslation = new Vector2D(e.Delta.Translation.X, e.Delta.Translation.Y);
                Vector2D localTranslation = globalTranslation.RotateClockWise(rotation);
                                
                double height = viewModel.Height + localTranslation.Y;

                if (height.IsRealNumber() && height > 5)
                {
                    viewModel.Height = height;
                }

                this.ViewModel.LastUsedShape = viewModel;
            }
        }

        private void WidthScale_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.IsInertial)
            {
                return;
            }

            FrameworkElement shape = sender as FrameworkElement;
            var viewModel = shape.DataContext as RectangleViewModel;

            if (viewModel != null)
            {
                double rotation = viewModel.Rotation * Math.PI / 180;

                Vector2D globalTranslation = new Vector2D(e.Delta.Translation.X, e.Delta.Translation.Y);
                Vector2D localTranslation = globalTranslation.RotateClockWise(rotation);

                double width = viewModel.Width + localTranslation.X;

                if (width.IsRealNumber() && width > 5)
                {
                    viewModel.Width = width;
                }

                this.ViewModel.LastUsedShape = viewModel;
            }
        }

        private void ScaleBall_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.IsInertial)
            {
                return;
            }

            FrameworkElement shape = sender as FrameworkElement;
            var viewModel = shape.DataContext as CircleViewModel;

            if (viewModel != null)
            {
                Vector2D translation = new Vector2D(e.Delta.Translation.X, e.Delta.Translation.Y);
                Vector2D diagonalVector = new Vector2D(viewModel.Radius, -viewModel.Radius);
                Vector2D newDiagonalVector = diagonalVector + translation;

                double radius = Math.Min(Math.Abs(newDiagonalVector.X), Math.Abs(newDiagonalVector.Y));

                if (radius.IsRealNumber() && radius > 5)
                {
                    viewModel.Diameter = radius * 2;
                }

                this.ViewModel.LastUsedShape = viewModel;
            }
        }
    }
}
